//
//  cAnimationManager.cpp
//  Spriter-Cocos2d-X
//
//  Created by qibinyi on 1/13/13.
//
//

#include "cAnimationManager.h"


#pragma mark SpriterConfigNode
SpriterConfigNode::SpriterConfigNode()
{
    this->_children = new CCArray();
    this->_properties = new CCDictionary();
    this->_parent = NULL;
}

SpriterConfigNode::~SpriterConfigNode()
{
    //qibinyi
    CC_SAFE_DELETE(this->_children);
    CC_SAFE_DELETE(this->_properties);
}

SpriterConfigNode* SpriterConfigNode::create(const char *name)
{
    SpriterConfigNode *node = new SpriterConfigNode();
    //qibinyi
    node->autorelease();
    
    node->_name = name;
    
    return node ;
}

SpriterConfigNode* SpriterConfigNode::getParent()
{
    return this->_parent;
}

void SpriterConfigNode::setParent(SpriterConfigNode *parent)
{
    this->_parent = parent;
}

const char* SpriterConfigNode::getName()
{
    return this->_name;
}

CCArray* SpriterConfigNode::getChildren()
{
    return this->_children;
}

SpriterConfigNode* SpriterConfigNode::getChildrenAt(int index)
{
    if (index<_children->count())
    {
        return (SpriterConfigNode*)_children->objectAtIndex(index);
    }
    
    return NULL;
}

int SpriterConfigNode::getChildrenCount()
{
    return _children->count();
}

CCDictionary* SpriterConfigNode::getProperties()
{
    return this->_properties;
}

CCString* SpriterConfigNode::getPropertyCCString(const char *key)
{
    CCObject *obj = _properties->objectForKey(key);
    
    if (obj)
    {
        return (CCString*)obj;
    }
    
    return CCString::create("");
}

#pragma mark SpriterObjectRef
SpriterObjectRef* SpriterObjectRef::create()
{
    SpriterObjectRef* ref = new SpriterObjectRef();
    //qibinyi
    ref->autorelease();
    return ref ;
}

int SpriterObjectRef::getTimelineId()
{
    return _timelineId;
}

void SpriterObjectRef::setTimelineId(int timelineId)
{
    _timelineId = timelineId;
}

int SpriterObjectRef::getTimelineKey()
{
    return _timelineKey;
}

void SpriterObjectRef::setTimelineKey(int timelineKey)
{
    _timelineKey = timelineKey;
}
#pragma mark TGSpriterMainlineKey

SpriterMainlineKey* SpriterMainlineKey::create()
{
    SpriterMainlineKey *key = new SpriterMainlineKey();
    
    key->_objectRefs = new CCArray();
    //qibinyi
    key->autorelease();
    
    return key;
}

SpriterMainlineKey::~SpriterMainlineKey() {
    //tested
    CC_SAFE_DELETE(this->_objectRefs);
    
}

void SpriterMainlineKey::addObjectRef(SpriterObjectRef *objectRef)
{
    _objectRefs->addObject(objectRef);
}

CCArray* SpriterMainlineKey::getObjectRefs()
{
    return _objectRefs;
}

SpriterTimeline* SpriterTimeline::create()
{
    SpriterTimeline *line = new SpriterTimeline();
    line->_keys = new CCArray();
    
    //qibinyi
    line->autorelease();
    //    line->_keys->autorelease();
    return line;
}

SpriterTimeline::~SpriterTimeline()
{
    CC_SAFE_DELETE(this->_keys);
    
}

void SpriterTimeline::addKeyFrame(SpriterTimelineKey *frame)
{
    _keys->addObject(frame);
}

CCArray* SpriterTimeline::getKeys()
{
    return _keys;
}

SpriterTimelineKey* SpriterTimelineKey::create()
{
    SpriterTimelineKey *key = new SpriterTimelineKey();
    //qibinyi
    key->autorelease();
    
    return key;
}

int SpriterTimelineKey::getFileId()
{
    return _file;
}

void SpriterTimelineKey::setFileId(int id)
{
    _file = id;
}

int SpriterTimelineKey::getFolderId()
{
    return _folder;
}

void SpriterTimelineKey::setFolderId(int id)
{
    _folder = id;
}

double SpriterTimelineKey::getStartsAt()
{
    return _startsAt;
}

void SpriterTimelineKey::setStartsAt(double index)
{
    _startsAt = index;
}

CCPoint SpriterTimelineKey::getPostion()
{
    return _position;
}

void SpriterTimelineKey::setPostion(cocos2d::CCPoint postion)
{
    _position = postion;
}

CCPoint SpriterTimelineKey::getAnchorPoint()
{
    return _anchorPoint;
}

void SpriterTimelineKey::setAnchorPoint(cocos2d::CCPoint anchorPoint)
{
    _anchorPoint = anchorPoint;
}

double SpriterTimelineKey::getRotation()
{
    return _rotation;
}

void SpriterTimelineKey::setRotation(double rotation)
{
    _rotation = rotation;
}

int SpriterTimelineKey::getSpin()
{
    return _spin;
}

void SpriterTimelineKey::setSpin(int spin)
{
    _spin = spin;
}

double SpriterTimelineKey::getScaleX()
{
    return _scaleX;
}

void SpriterTimelineKey::setScaleX(double scaleX)
{
    _scaleX = scaleX;
}

double SpriterTimelineKey::getScaleY()
{
    return _scaleY;
}

void SpriterTimelineKey::setScaleY(double scaleY)
{
    _scaleY = scaleY;
}

SpriterAnimation::SpriterAnimation()
{
    _name = NULL ;
    _mainline = new CCArray();
    _timelines = new CCArray();
}

SpriterAnimation::~SpriterAnimation()
{
    
    CC_SAFE_RELEASE(_name);
    
    if (_mainline)
    {
        _mainline->removeAllObjects();
        _mainline->release();
        _mainline = NULL;
    }
    if (_timelines)
    {
        _timelines->removeAllObjects();
        _timelines->release();
        _timelines = NULL;
    }
}

SpriterAnimation* SpriterAnimation::create()
{   SpriterAnimation* sprAnim =  new SpriterAnimation() ;
    
    //qibinyi
    sprAnim->autorelease();
    return sprAnim ;
}

const char* SpriterAnimation::getName()
{
    //CCLog("get name: %s , addr: %d" , this->_name->getCString() , this->_name );
    return this->_name->getCString();
}

void SpriterAnimation::addKeyFrame(SpriterMainlineKey *frame)
{
    _mainline->addObject(frame);
}

void SpriterAnimation::setName(const char *name)
{
    //CCLog("set name: %s" , name);
    CC_SAFE_RELEASE(this->_name);
    this->_name = CCString::create(name) ;
    this->_name->retain();
}

double SpriterAnimation::getDuration()
{
    return this->_duration;
}

void SpriterAnimation::setDuration(double duration)
{
    this->_duration = duration;
}

void SpriterAnimation::addTimeline(SpriterTimeline *timeline)
{
    _timelines->addObject(timeline);
}

CCArray* SpriterAnimation::getMainline()
{
    return _mainline;
}

CCArray* SpriterAnimation::getTimelines()
{
    return _timelines;
}


// cAnimation

cAnimation::cAnimation()
{
 
    
    _configRoot = NULL;
    _curConfigNode = NULL;
    
    
    _animations = new CCDictionary();
    _frames = new CCDictionary();
    
    _files = new CCDictionary();
    
    

}

cAnimation::~cAnimation()
{
    if (_animations)
    {
        _animations->release();
        _animations = NULL;
    }
    
    
    if (_frames)
    {
        _frames->release();
        _frames = NULL;
    }
    
    
    if (_files)
    {
        _files->release();
        _files = NULL;
    }

}

cAnimation* cAnimation::create(const char *scmlFile, const char *plistFile)
{
    std::string str_scml = scmlFile;
    size_t endtPos = str_scml.find_last_of("/");
    str_scml = str_scml.erase(0 , endtPos+1);
    
    const char * key = str_scml.c_str();
    
    //CCLog("%s" , key ) ;
    
    CCObject* anim = cAnimationManager::instance().animManager->objectForKey( key );
    //TODO
    if ( anim == NULL ) {
        CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile( plistFile );
        
        cAnimation * pNode = new cAnimation();
        
        if (pNode->initNodeWithFile(scmlFile))
        {
            pNode->autorelease();
            cAnimationManager::instance().animManager->setObject(pNode, key);
            
            return pNode;
        }
        
        CC_SAFE_DELETE(pNode);
        return NULL;
        
    }
    else {
        return (cAnimation*)anim;
    }
    
    

}



void cAnimation::startElement(void *ctx, const char *name, const char **atts)
{
    CC_UNUSED_PARAM(ctx);
    
    if ( _configRoot == NULL)
    {
        _configRoot = SpriterConfigNode::create( name );
        _curConfigNode = _configRoot;
        return;
    }
    
    SpriterConfigNode *newNode = SpriterConfigNode::create( name );
    
    newNode->setParent( _curConfigNode );
    
    if (atts && atts[0]) {
        for (int i=0; atts[i]; i+=2)
        {
            std::string key = (char*)atts[i];
            std::string value = (char*)atts[i+1];
            
            newNode->getProperties()->setObject( CCString::create( value ), key );
        }
    }
    
    _curConfigNode->getChildren()->addObject( newNode );
    _curConfigNode = newNode;
}

void cAnimation::endElement(void *ctx, const char *name)
{
    _curConfigNode = _curConfigNode->getParent();
}

void cAnimation::textHandler(void *ctx, const char *ch, int len)
{
}





bool cAnimation::initNodeWithFile(const char *scmlFile)
{
    CCAssert(scmlFile != NULL && strlen(scmlFile)>0, "SpriterNode: SCML file should not be NULL");
    
    
    
    const char *path = CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(scmlFile);
    
    CCSAXParser parser;
    
    if (false == parser.init("UTF-8") )
    {
        return false;
    }
    
    parser.setDelegator(this);
    
    bool rs = parser.parse(path);
    
    initObjects();
    
    return rs;
}

void cAnimation::initObjects()
{
    for (int i=0; i<_configRoot->getChildrenCount(); i++)
    {
        SpriterConfigNode *c = _configRoot->getChildrenAt(i);
        //CCLog("%s", c->getName());
        
        if (!strncmp(c->getName(), "folder", strlen(c->getName())))
        {
            for (int j=0; j<c->getChildrenCount(); j++)
            {
                SpriterConfigNode *file = c->getChildrenAt(j);
                
                CCString *fileKey =
                CCString::createWithFormat(
                                           "%d-%d",
                                           c->getPropertyCCString("id")->intValue(),
                                           file->getPropertyCCString("id")->intValue());
                
                std::string strFile = (char*)file->getPropertyCCString("name")->getCString();
                std::string pattern = "/";
                
                std::string::size_type pos;
                std::vector<std::string> result;
                
                strFile += pattern;
                
                int size = strFile.size();
                
                for (int i=0; i<size; i++)
                {
                    pos = strFile.find(pattern, i);
                    
                    if(pos<size)
                    {
                        std::string s = strFile.substr(i, pos-i);
                        result.push_back(s);
                        i=pos+pattern.size()-1;
                    }
                }
                
                std::string _file = result[result.size()-1];
                
                //CCLog("%s", CCString::create(_file)->getCString());
                
                _files->setObject(CCString::create(_file), fileKey->getCString());
            }
        }
        else if(!strncmp(c->getName(), "entity", strlen(c->getName())))
        {
            for (int k=0; k<c->getChildrenCount(); k++)
            {
                SpriterConfigNode *animation = c->getChildrenAt(k);
                
                SpriterAnimation *spriterAnimation = SpriterAnimation::create();
                spriterAnimation->setName(animation->getPropertyCCString("name")->getCString());
                spriterAnimation->setDuration(animation->getPropertyCCString("length")->doubleValue());
                
                //CCLog("Parsing Animation: %s %f", spriterAnimation->getName(), spriterAnimation->getDuration());
                
                for (int l=0; l<animation->getChildrenCount(); l++)
                {
                    SpriterConfigNode *animConfig = animation->getChildrenAt(l);
                    
                    if (!strncmp(animConfig->getName(), "mainline", strlen(animConfig->getName())))
                    {
                        for (int m=0; m<animConfig->getChildrenCount(); m++)
                        {
                            SpriterConfigNode *key = animConfig->getChildrenAt(m);
                            SpriterMainlineKey *mainlineKey = SpriterMainlineKey::create();
                            
                            for (int n=0; n<key->getChildrenCount(); n++)
                            {
                                SpriterConfigNode *object_ref = key->getChildrenAt(n);
                                
                                SpriterObjectRef *objectRef = SpriterObjectRef::create();
                                
                                objectRef->setTimelineId(object_ref->getPropertyCCString("timeline")->intValue());
                                objectRef->setTimelineKey(object_ref->getPropertyCCString("key")->intValue());
                                
                                mainlineKey->addObjectRef(objectRef);
                            }
                            spriterAnimation->addKeyFrame(mainlineKey);
                        }
                    }
                    else if(!strncmp(animConfig->getName(), "timeline", strlen(animConfig->getName())))
                    {
                        SpriterTimeline *timeline = SpriterTimeline::create();
                        
                        for (int p=0; p<animConfig->getChildrenCount(); p++)
                        {
                            SpriterConfigNode *key = animConfig->getChildrenAt(p);
                            
                            for (int q=0; q<key->getChildrenCount(); q++)
                            {
                                SpriterConfigNode *object = key->getChildrenAt(q);
                                
                                SpriterTimelineKey *timelineKey = SpriterTimelineKey::create();
                                
                                timelineKey->setFolderId(object->getPropertyCCString("folder")->intValue());
                                timelineKey->setFileId(object->getPropertyCCString("file")->intValue());
                                timelineKey->setPostion(
                                                        ccp(object->getPropertyCCString("x")->doubleValue()/CC_CONTENT_SCALE_FACTOR(),
                                                            object->getPropertyCCString("y")->doubleValue()/CC_CONTENT_SCALE_FACTOR()) );
                                
                                
                                // revised by qibinyi@gmail.com,  20130111
                                //*
                                double pivot_y = object->getPropertyCCString("pivot_y")->doubleValue();
                                if ( pivot_y == 0 )
                                {
                                    if ( strcmp(object->getPropertyCCString("pivot_y")->getCString(),"" )==0 )
                                        pivot_y = 1 ;
                                }
                                
                                timelineKey->setAnchorPoint(
                                                            ccp(object->getPropertyCCString("pivot_x")->doubleValue(), pivot_y ));
                                /*/
                                 timelineKey->setAnchorPoint(
                                 ccp(object->getPropertyCCString("pivot_x")->doubleValue(),
                                 object->getPropertyCCString("pivot_y")->doubleValue()));
                                 //*/
                                
                                
                                timelineKey->setStartsAt(key->getPropertyCCString("time")->doubleValue());
                                timelineKey->setRotation(object->getPropertyCCString("angle")->doubleValue());
                                
                                if(object->getPropertyCCString("scale_x")->doubleValue())
                                {
                                    timelineKey->setScaleX(object->getPropertyCCString("scale_x")->doubleValue());
                                }
                                else
                                {
                                    timelineKey->setScaleX(1.0);
                                }
                                
                                if(object->getPropertyCCString("scale_y")->doubleValue())
                                {
                                    timelineKey->setScaleY(object->getPropertyCCString("scale_y")->doubleValue());
                                }
                                else
                                {
                                    timelineKey->setScaleY(1.0);
                                }
                                
                                
                                if (key->getPropertyCCString("spin")->intValue())
                                {
                                    timelineKey->setSpin(key->getPropertyCCString("spin")->intValue());
                                }
                                else
                                {
                                    timelineKey->setSpin(1);
                                }
                                
                                timeline->addKeyFrame(timelineKey);
                            }
                        }
                        
                        spriterAnimation->addTimeline(timeline);
                    }
                }
                
                _animations->setObject(spriterAnimation, spriterAnimation->getName());
            }
        }
    }
    
    if ( _configRoot )
    {
        _configRoot->release();
        _configRoot = NULL;
    }
}


